package cn.xinfei.xdecision.engine.runner.executor.handler;

import cn.xinfei.xdecision.common.model.component.decisiontree.DecisionTreeDetail;
import cn.xinfei.xdecision.common.model.component.decisiontree.DecisionTreeDetailCondition;
import cn.xinfei.xdecision.common.model.component.decisiontree.vo.DecisionTreeVersionVo;
import cn.xinfei.xdecision.common.model.enginex.runner.ExpressionParam;
import cn.xinfei.xdecision.common.utils.constant.runner.ParamTypeConst;
import cn.xinfei.xdecision.common.utils.util.runner.jeval.EvaluationException;
import cn.xinfei.xdecision.engine.runner.context.AmmunitionDepot;
import cn.xinfei.xdecision.engine.runner.expressions.ExpressExecutor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
@Slf4j
public class DecisionTreeNodeHandler {
    public Object executeDecisionTree(DecisionTreeVersionVo version) throws EvaluationException {
        List<DecisionTreeDetail> detailList = version.getDetailList();
        for (DecisionTreeDetail decisionTreeDetail : detailList) {
            Object o = executeDecisionTreeDetail(decisionTreeDetail);
            if (o != null) {
                return o;
            }
        }
        return null;
    }

    public Object executeDecisionTreeDetail(DecisionTreeDetail detail) throws EvaluationException {
        //获取需要执行的条件列表
        List<DecisionTreeDetailCondition> conditionList = detail.getConditionList();
        String fieldEn = detail.getFieldCode();
        String logical = detail.getLogicalSymbol();
        boolean result = false;
        //根据不通关系进行处理
        switch (logical) {
            case "||":
                result = false;
                for (DecisionTreeDetailCondition condition : conditionList) {
                    ExpressionParam expressionParam = new ExpressionParam();
                    BeanUtils.copyProperties(condition, expressionParam);
                    expressionParam.setFieldEn(fieldEn);
                    boolean expressionResult = ExpressExecutor.getExpressionResult(expressionParam);
                    if (expressionResult) {
                        result = true;
                        break;
                    }
                }
                break;
            case "&&":
                result = true;
                for (DecisionTreeDetailCondition condition : conditionList) {
                    ExpressionParam expressionParam = new ExpressionParam();
                    BeanUtils.copyProperties(condition, expressionParam);
                    expressionParam.setFieldEn(fieldEn);
                    boolean expressionResult = ExpressExecutor.getExpressionResult(expressionParam);
                    if (!expressionResult) {
                        result = false;
                        break;
                    }
                }
                break;
        }
        //如果本节点符合则执行后续节点
        if (result) {
            Integer type = detail.getNodeType();
            List<DecisionTreeDetail> children = detail.getChildren();
            if (type == null) {
                if (children == null || children.isEmpty()) {
                    type = 2;
                } else {
                    type = 1;
                }
            }
            if (type != null) {
                switch (type) {
                    //普通节点符合，让子节点继续执行。
                    case 1:
                        if (children != null && children.size() > 0) {
                            for (DecisionTreeDetail child : children) {
                                Object executeResult = this.executeDecisionTreeDetail(child);
                                if (executeResult != null) {
                                    return executeResult;
                                }
                            }
                        }
                        break;
                    //叶子节点符合，返回叶子节点的值。
                    case 2:
                        //如果是变量则查询值，如果是常量直接输出
                        if (detail.getValueType() == ParamTypeConst.VARIABLE) {
                            return AmmunitionDepot.getValueByKeyFromRemote(ParamTypeConst.VARIABLE, detail.getResultValue(), detail.getResultValue());
                        }
                        return detail.getResultValue();
                    default:
                        break;
                }
            }
        }
        return null;
    }


}
